#include "mix.hh"

ApplyMean::ApplyMean (IplImage* input1_,
		      IplImage* input2_)
  : input1(input1_),
    input2(input2_)
{
  output = cvCreateImage (cvSize (input1->width, input1->height), IPL_DEPTH_8U, 3); 
}

void ApplyMean::operator() (const tbb::blocked_range2d<int>& r) const
{
  for (int i = r.rows().begin(); i!= r.rows().end(); ++i)
    for (int j = r.cols().begin(); j!= r.cols().end(); ++j)
      {
	CvScalar s1 = cvGet2D (input1, i, j);
	CvScalar s2 = cvGet2D (input2, i, j);
	s1.val[0] = (s1.val[0] + s2.val[0]) / 2;
	s1.val[1] = (s1.val[1] + s2.val[1]) / 2;
	s1.val[2] = (s1.val[2] + s2.val[2]) / 2;
	cvSet2D (output, i, j, s1);
      }
}

IplImage*
ApplyMean::getOutput ()
{
  return output;
}


ApplyDiffAbs::ApplyDiffAbs (IplImage* input1_,
			    IplImage* input2_)
  : input1(input1_),
    input2(input2_)
{
  output = cvCreateImage (cvSize (input1->width, input1->height), IPL_DEPTH_8U, 3); 
}

void ApplyDiffAbs::operator() (const tbb::blocked_range2d<int>& r) const
{
  for (int i = r.rows().begin(); i!= r.rows().end(); ++i)
    for (int j = r.cols().begin(); j!= r.cols().end(); ++j)
      {
	CvScalar s1 = cvGet2D (input1, i, j);
	CvScalar s2 = cvGet2D (input2, i, j);
	s1.val[0] = ((s1.val[0] - s2.val[0]) < 0) ? (s2.val[0] - s1.val[0]) : (s1.val[0] - s2.val[0]);
	s1.val[1] = ((s1.val[1] - s2.val[1]) < 0) ? (s2.val[1] - s1.val[1]) : (s1.val[1] - s2.val[1]);
	s1.val[2] = ((s1.val[2] - s2.val[2]) < 0) ? (s2.val[2] - s1.val[2]) : (s1.val[2] - s2.val[2]);
	cvSet2D (output, i, j, s1);
      }
}

IplImage*
ApplyDiffAbs::getOutput ()
{
  return output;
}


IplImage*
mix (IplImage* input1,
     IplImage* input2,
     const char *op)
{
  if (op[0] == 'm' && op[1] == 'e' && op[2] == 'a' && op[3] == 'n')
    {
      ApplyMean app(input1, input2);
      tbb::parallel_for(tbb::blocked_range2d<int>(0,input1->height, 0,input1->width),
			app, tbb::auto_partitioner());
      return app.getOutput ();
    }

  if (op[0] == 'd' && op[1] == 'i' && op[2] == 'f' && op[3] == 'f')
    {
      ApplyDiffAbs app(input1, input2);
      tbb::parallel_for(tbb::blocked_range2d<int>(0,input1->height, 0,input1->width),
			app, tbb::auto_partitioner());
      return app.getOutput ();
    }

  return NULL;
}
